package cn.wk.user.service.impl;

import cn.wk.basic.constant.ConstantPethome;
import cn.wk.basic.constant.ConstantVerification;
import cn.wk.basic.constant.ConstantWechat;
import cn.wk.basic.exception.DiyException;
import cn.wk.basic.utils.HttpClientUtils;
import cn.wk.user.domain.LoginInfo;
import cn.wk.user.domain.User;
import cn.wk.user.domain.Wechat;
import cn.wk.user.domain.dto.LoginInfoDto;
import cn.wk.user.mapper.LoginInfoMapper;
import cn.wk.user.mapper.UserMapper;
import cn.wk.user.mapper.WechatMapper;
import cn.wk.user.service.IWechatService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class WechatServiceImpl implements IWechatService {
    @Autowired
    private WechatMapper wechatMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private LoginInfoMapper loginInfoMapper;
    @Autowired
    private UserMapper userMapper;
    /**
     * 通过code获取token和处理其他业务
     * @param code
     */
    @Override
    public Map<String, Object> getToken(String code) {
        HashMap<String, Object> map = new HashMap<>();

        //获取微信token的url
        String wxTokenUrl = ConstantWechat.TOKEN_URL.replace("APPID",ConstantWechat.APPID)
                .replace("SECRET",ConstantWechat.SECRET).replace("CODE",code);
        //携带code去获取令牌
        String wxToken = HttpClientUtils.httpGet(wxTokenUrl);
//        System.out.println(wxToken);
        //转换成json格式
        JSONObject jsonwxToken = JSONObject.parseObject(wxToken);
//        System.out.println(jsonObject);
        String access_token = jsonwxToken.getString("access_token");
//        System.out.println(access_token);
        String openid = jsonwxToken.getString("openid");
        //发送get请求，获取个人信息
        String information = HttpClientUtils.httpGet(ConstantWechat.USER_INFORMATION_URL.replace("ACCESS_TOKEN", access_token))
                .replace("OPENID", openid);
//        System.out.println(information);
        //转换成json格式
        JSONObject jsonInfo = JSONObject.parseObject(information);
//        System.out.println(jsonInfo.getString("openid"));
        //判断用户是否第一次扫码，先要去查询数据库t_wxuser，顺便连表查询把logininfo也查询了因为可以看其是否已经绑定手机号
        Wechat dbwechat = wechatMapper.findByOpenid(openid);
        //如果不存在先把其数据保存在表里
        if(dbwechat == null){
            Wechat wechat = new Wechat();
            //为空的话直接往里面添加数据
            wechat.setOpenid(jsonInfo.getString("openid"));
            wechat.setAddress(jsonInfo.getString("country"));
            wechat.setHeadimgurl(jsonInfo.getString("headimgurl"));
            wechat.setNickname(jsonInfo.getString("nickname"));
            wechat.setSex(jsonInfo.getInteger("sex"));
            //保存
            wechatMapper.save(wechat);
            //给前端响应一个状态，让前端去进行跳转到绑定界面，让其携带openid，因为绑定也要根据openid
            //前端如果看到有openid就进行跳转绑定
            map.put("openid",openid);
            return map;
        }else{  //这里证明不是第一次扫码，去获取其logininfo_id，看其是否绑定，没绑定依然携带openid进行绑定跳转
            LoginInfo logininfo = dbwechat.getLogininfo();
            if(logininfo == null){
                map.put("openid",openid);
                return map;
            }
            //这里说明wxuser和logininfo都不为null，就应该直接登录
            //redis中有logininfo数据，就代表登录了
            String token = UUID.randomUUID().toString();
            //往redis中存值
            redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);
            //返回给前台
            map.put("token",token);
            map.put("loginUser",logininfo);
            return map;
        }
    }

    /**
     * 微信用户与手机号进行绑定
     * @return
     */
    @Override
    public Map<String, Object> theBinding(LoginInfoDto loginInfoDto) throws DiyException {
        //校验数据
        checkTheBindData(loginInfoDto);
        //根据手机号和type去查询
        LoginInfo loginInfo = loginInfoMapper.findByNameAndType(loginInfoDto.getPhone(), loginInfoDto.getType());
        //看其是否已经绑定
        if(loginInfo == null){
            //保存数据，先保存login登录信息表，再保存user表，然后更新wxuser表把logininfoid进行赋值
            //创建logininfo对象
            loginInfo = createLoginInfo(loginInfoDto);
            //保存
            loginInfoMapper.save(loginInfo);
            //通过logininfo创建user对象
            User user = createUser(loginInfo);
            //保存
            userMapper.save(user);
        }
        HashMap<String, Object> map = new HashMap<>();
        //更新wxuser表把logininfoid进行赋值
        //去更新
        wechatMapper.addWxuserInLogininfoid(loginInfo.getId(),loginInfoDto.getOpenid());
        //这里绑定成功，要直接登录，redis有值就说明登录
        //创建token
        String token = UUID.randomUUID().toString();
        //往redis中存值
        redisTemplate.opsForValue().set(token,loginInfo,30, TimeUnit.MINUTES);
        //返回给前端
        map.put("token",token);
        map.put("loginUser",loginInfo);
        return map;
    }

    /**
     * 通过loginInfo创建user对象
     * @param loginInfo
     * @return
     */
    private User createUser(LoginInfo loginInfo) {
        User user = new User();
        BeanUtils.copyProperties(loginInfo,user);
        user.setState(ConstantPethome.OK);
        user.setLogininfo(loginInfo);
        return user;
    }

    /**
     * 通过loginInfoDto进行创建logininfo对象
     * @param loginInfoDto
     */
    private LoginInfo createLoginInfo(LoginInfoDto loginInfoDto) {
        LoginInfo loginInfo = new LoginInfo();
        loginInfo.setType(loginInfoDto.getType());
        loginInfo.setPhone(loginInfoDto.getPhone());
        return loginInfo;
    }

    /**
     * 校验前端微信与绑定手机号传过来的数据
     * @param loginInfoDto
     */
    private void checkTheBindData(LoginInfoDto loginInfoDto) throws DiyException {
        if(StringUtils.isEmpty(loginInfoDto.getPhone())){
            throw new DiyException("请输入绑定手机号");
        }
        if(StringUtils.isEmpty(loginInfoDto.getCode())){
            throw new DiyException("请输入验证码");
        }
        //去redis中获取当时存入的验证码和输入的验证码进行对比
        String redisKey = loginInfoDto.getPhone()+":"+ ConstantVerification.USE_BINDER;
        String codeVal = (String)redisTemplate.opsForValue().get(redisKey);
        System.out.println(codeVal);
        if(StringUtils.isEmpty(codeVal)){
            throw new DiyException("请先获取验证码");
        }
        if(!loginInfoDto.getCode().equals(codeVal.split(":")[0])){
            throw new DiyException("验证码输入错误");
        }
        if(StringUtils.isEmpty(codeVal)){
            throw new DiyException("验证码已经过期，请重新获取");
        }
        if(StringUtils.isEmpty(loginInfoDto.getType())){
            throw new DiyException("请完善信息");
        }
        if(StringUtils.isEmpty(loginInfoDto.getOpenid())){
            throw new DiyException("请完善信息");
        }
    }
}
